package com.yungu.swift.system.sys.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.base.mapper.IMapper;
import com.yungu.swift.base.model.PageVo;
import com.yungu.swift.base.model.config.ServerConfig;
import com.yungu.swift.base.service.impl.BaseServiceImpl;
import com.yungu.swift.constants.FinanceConstant;
import com.yungu.swift.system.config.ApplicationConfig;
import com.yungu.swift.system.finance.model.dto.FinanceOrderDto;
import com.yungu.swift.system.finance.model.enums.FinanceEnum;
import com.yungu.swift.system.finance.model.param.AdminAccountFlowPageParam;
import com.yungu.swift.system.finance.model.param.AdminAccountPageParam;
import com.yungu.swift.system.finance.service.FinanceOrderService;
import com.yungu.swift.system.finance.service.FinanceRefundService;
import com.yungu.swift.system.sys.dao.SysAccountDriverMapper;
import com.yungu.swift.system.sys.model.dto.SysAccountDriverDto;
import com.yungu.swift.system.sys.model.vo.SysDriverAccountFlowVo;
import com.yungu.swift.system.sys.model.vo.SysDriverAccountVo;
import com.yungu.swift.system.sys.service.SysAccountDriverService;
import com.yungu.swift.utils.ParamUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Service
public class SysAccountDriverServiceImpl extends BaseServiceImpl<SysAccountDriverDto> implements SysAccountDriverService {

    @Autowired
    private SysAccountDriverMapper sysAccountDriverMapper;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Reference
    private FinanceOrderService financeOrderService;
    @Reference
    private SysAccountDriverService sysAccountDriverService;
    @Reference
    private FinanceRefundService financeRefundService;

    @Override
    protected IMapper<SysAccountDriverDto> getMapper() {
        return sysAccountDriverMapper;
    }

    @Override
    public ResponseData<PageVo<SysDriverAccountVo>> queryPageVo(AdminAccountPageParam pageParam) {
        PageBounds pageBounds = new PageBounds(pageParam.getPageNum(), pageParam.getPageSize());
        PageList<SysDriverAccountVo> pageList = sysAccountDriverMapper.queryPageVo(pageParam, pageBounds);
        PageVo<SysDriverAccountVo> pageVo = new PageVo(pageParam.getPageNum(), pageParam.getPageSize(),
                pageList.getPaginator().getTotalCount());
        pageVo.setItems(pageList);
        return ResponseData.buildSuccessResponse(pageVo);
    }

    @Override
    public ResponseData<List<SysDriverAccountVo>> export(AdminAccountPageParam pageParam) {
        return ResponseData.buildSuccessResponse(sysAccountDriverMapper.queryPageVo(pageParam));
    }

    @Override
    public ResponseData<SysDriverAccountVo> statistics(AdminAccountPageParam pageParam) {
        return ResponseData.buildSuccessResponse(sysAccountDriverMapper.statistics(pageParam));
    }

    @Override
    public ResponseData<PageVo<SysDriverAccountFlowVo>> flowQueryPage(AdminAccountFlowPageParam flowPageParam) {
        PageBounds pageBounds = new PageBounds(flowPageParam.getPageNum(), flowPageParam.getPageSize());
        PageList<SysDriverAccountFlowVo> pageList = sysAccountDriverMapper.flowQueryPage(flowPageParam, pageBounds);
        PageVo<SysDriverAccountFlowVo> pageVo = new PageVo(flowPageParam.getPageNum(), flowPageParam.getPageSize(),
                pageList.getPaginator().getTotalCount());
        fillDate(pageList, flowPageParam.getUuid());
        pageVo.setItems(pageList);
        return ResponseData.buildSuccessResponse(pageVo);
    }

    @Override
    public ResponseData<List<SysDriverAccountFlowVo>> flowExport(AdminAccountFlowPageParam flowPageParam) {
        List<SysDriverAccountFlowVo> flowVoList = sysAccountDriverMapper.flowQueryPage(flowPageParam);
        fillDate(flowVoList, flowPageParam.getUuid());
        return ResponseData.buildSuccessResponse(flowVoList);
    }

    /**
     * 补充数据含义
     *
     * @param list
     * @param uuid
     */
    private void fillDate(List<SysDriverAccountFlowVo> list, String uuid) {
        list.stream().forEach(accountFlowVo -> {
            accountFlowVo.setCourseDescription(FinanceEnum.getMsg(accountFlowVo.getCourse()));
            accountFlowVo.setTransactionType(Objects.equals(accountFlowVo.getFinanceInflow(), uuid) ? "收入" : "支出");
        });
    }

    @Override
    public ResponseData<SysDriverAccountVo> findAccountDriverVo(Map<String, Object> map) {
        return ResponseData.buildSuccessResponse(sysAccountDriverMapper.findAccountDriverVo(map));
    }

    @Override
    public ResponseData<Boolean> thawDriverFrozenBalance() {
        log.info("-----结转司机冻结金额开始-----");
        //获取解冻时间设置
        ServerConfig.SystemBean system = ApplicationConfig.SERVER_CONFIG.getSystem();
        //获取距离当前thawDay天可以解冻的流水
        ResponseData<List<FinanceOrderDto>> responseData = financeOrderService.findByThawDay(system.getThawDay());
        if (!responseData.isSuccess() || responseData.getData() == null) {
            log.info("司机冻结金额可提现，没有可处理的流水信息");
            return ResponseData.buildSuccessResponse(Boolean.TRUE);
        }
        for (FinanceOrderDto financeOrder : responseData.getData()) {
            //可以转提现的金额
            BigDecimal canFrowardAmount = financeOrder.getAmount();
            //查询该笔订单是否有退款
            ResponseData<BigDecimal> findRefundAmount = financeRefundService.findRefundAmount(financeOrder.getOrderUuid());
            if (findRefundAmount.isSuccess() && ParamUtil.defaultIfNull(findRefundAmount.getData(), BigDecimal.ZERO).compareTo(BigDecimal.ZERO) == 1) {
                canFrowardAmount = canFrowardAmount.subtract(findRefundAmount.getData());
            }
            //获取司机账户
            ResponseData<SysAccountDriverDto> getDriverAccount = sysAccountDriverService.get(financeOrder.getFinanceInflow());
            if (!getDriverAccount.isSuccess() || getDriverAccount.getData() == null) {
                log.info("{}获取不到司机账号,结转失败", financeOrder.getFinanceInflow());
                continue;
            }
            SysAccountDriverDto accountDriverDto = getDriverAccount.getData();
            //修改司机账户
            BigDecimal canFrowardBalance = accountDriverDto.getCanFrowardBalance().add(canFrowardAmount);
            BigDecimal frozenBalance = accountDriverDto.getFrozenBalance().subtract(canFrowardAmount);
            //防止冻结余额为负数
            if (frozenBalance.compareTo(BigDecimal.ZERO) == -1) {
                log.info("司机{}冻结账户金额不足,结转失败", financeOrder.getFinanceInflow());
                continue;
            }
            accountDriverDto.setCanFrowardBalance(canFrowardBalance);
            accountDriverDto.setFrozenBalance(frozenBalance);
            accountDriverDto.setUpdateOn(new Date());

            //设置流水状态为司机抽成冻结转提现操作
            financeOrder.setStatus(FinanceConstant.THAW_BALANCE_STATUS);
            financeOrder.setUpdateOn(new Date());

            transactionTemplate.execute(transactionStatus -> {
                sysAccountDriverService.edit(accountDriverDto);
                financeOrderService.edit(financeOrder);
                return Boolean.TRUE;
            });
        }
        log.info("-----结转司机冻结金额完成-----");
        return ResponseData.buildSuccessResponse("司机冻结金额解冻成功", Boolean.TRUE);
    }

    @Override
    public ResponseData<Boolean> saveBatch(List<SysAccountDriverDto> list) {
        return ResponseData.buildSuccessResponse(sysAccountDriverMapper.saveBatch(list) > 0);
    }
}